#ifndef __KYO_LLIST_H__
#define __KYO_LLIST_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <my_debug.h>

//遍历链表回调函数
//第一个参数代表链表的数据元素的地址
//第二个参数代表使用者的通用参数地址
typedef void (llist_show_t)(void *, void *);
//数据元素比较回调函数
typedef int (llist_cmp_t)(const void *, const void *);
//销毁数据元素回调函数
typedef void (llist_destroy_t)(void *);
//存储加载回调函数
typedef int (llist_file_t)(void *, FILE *);

//前向声明
typedef struct llist_t LLIST;

//文件标识符
#define MAGIC       "KLIST"
#define MAGIC_LEN   6

//文件头信息结构体
typedef struct llist_file_head_t {
    char magic[MAGIC_LEN];      //文件标识符
    unsigned short check_sum;   //文件检验和
    int num;                    //链表元素个数
    int size;                   //链表元素大小
}DF_HEAD;

typedef struct node_t NODE;

struct node_t {
    void *data;
    NODE *prev;
    NODE *next;
};

struct llist_t {
    char magic[MAGIC_LEN];      //文件标识符
    unsigned short check_sum;   //文件检验和
    int num;            //数据元素个数
    int size;           //数据元素大小
    NODE head;          //链表的头
    void *tmp;          //临时数据元素中间变量
    llist_show_t *show;  //数据元素输出函数的地址
    llist_cmp_t *cmp;    //数据比较函数的地址
    llist_destroy_t *destroy; //数据销毁函数的地址
    llist_file_t *store; //存储回调函数
    NODE *data_count;     //llist_travel_data函数使用计数器 记录该返回第几个数据
    NODE *find_data_count;        //llist_travel_find_data函数使用计数器
    LLIST *find;         //保存查找结果的链表
};

//创建链表 初始化链表的数据成员
//size   创建什么数据元素的链表  每个数据元素占内存空间大小
LLIST *llist_create(int size, llist_show_t *show, llist_cmp_t *cmp, llist_destroy_t *destroy, llist_file_t *store);

//修改回调函数
//遍历回调函数 数据比较回调函数 数据销毁回调函数
//返回修改之前回调函数
llist_show_t *llist_set_show(llist_show_t *show, LLIST *handle);
llist_cmp_t *llist_set_cmp(llist_cmp_t *cmp, LLIST *handle);
llist_destroy_t *llist_set_destroy(llist_destroy_t *destroy, LLIST *handle);


//往链表尾插数据
//data  通用数据类型 数据大小取决于llist->size的值
//handle  标识哪个链表
int llist_append(void *data, LLIST *handle);
//往链表头插数据
//data  通用数据类型 数据大小取决于llist->size的值
//handle  标识哪个链表
int llist_prepend(void *data, LLIST *handle);
//往链表指定位置插入数据
//data  通用数据类型 数据大小取决于llist->size的值
//index 往链表哪个位置插入
#define LLIST_APPEND        -1
#define LLIST_INSERT_SORT   -2
#define LLIST_PREPEND       0
//  index == 0 || index < LLIST_INSERT_SORT   头插数据
//  index == LLIST_APPEND || index >= llist->num  尾插数据
//  index == LLIST_INSERT_SORT    有序插入
//  index   插入到index下标对应位置
//handle  标识哪个链表
int llist_insert(void *data, int index, LLIST *handle);
//从链表里删除指定位置的数据元素
//index 取值范围(0 ~ (llist->num - 1))
int llist_ind_delete(int index, LLIST *handle);

//从链表里删除指定数据 按关键词匹配数据
//key       通用数据类型的关键词的地址
//cmp       数据比较函数的地址
//flag      标识删除多个数据
//flag == 0 删除所有匹配数据
//flag > 0  删除匹配flag个数据(flag = 3 删除前三个匹配数据)
//flag < 0  删除匹配第(flag * -1)个数据(flag = -3 删除第三个匹配数据)
int llist_delete_cmp(void *key, llist_cmp_t *cmp, int flag, LLIST *handle);
//数据比较函数会调用llist->cmp 如果llist->cmp=NULL报错
int llist_delete(void *key, int flag, LLIST *handle);

//返回对应下标的数据元素地址
//index 取值范围(0 ~ (llist->num - 1))
void *llist_ind(int index, LLIST *handle);

//返回对应链表的数据元素内存空间大小
int llist_size(LLIST *handle);
//返回对应链表的数据元素个数
int llist_num(LLIST *handle);

//遍历链表 封装循环链表由使用者输出
//打印数据元素会调用参数show函数地址
//arg为show函数的参数(使用者的数据)
void llist_travel_show(llist_show_t *show, void *arg, LLIST *handle);
//打印数据元素会调用llist->show函数地址
void llist_travel(void *arg, LLIST *handle);

//遍历链表 调用一次返回一个数据 调用第二次返回第二个数据 ...
void *llist_travel_data(LLIST *handle);
//把llist_travel_data使用的计数器置0
void llist_travel_rewind(LLIST *handle);

//从链表里查找指定数据 按关键词匹配数据
//key       通用数据类型的关键词的地址
//cmp       数据比较函数的地址
//flag      标识查找多个数据
//flag == 0 查找所有匹配数据
//flag > 0  查找匹配flag个数据(flag = 3 查找前三个匹配数据)
//flag < 0  查找匹配第(flag * -1)个数据(flag = -3 查找第三个匹配数据)
//第二查找结果会覆盖第一次查找结果
int llist_find_cmp(void *key, llist_cmp_t *cmp, int flag, LLIST *handle);
//数据比较函数会调用llist->cmp函数 llist->cmp = NULL 会报错
int llist_find(void *key, int flag, LLIST *handle);
//遍历查找结果 封装循环以回调函数形式输出查找结果
void llist_travel_find_show(llist_show_t *show, void *arg, LLIST *handle);
void llist_travel_find(void *arg, LLIST *handle);
//遍历查找结果 调用一次返回第一个查找结果，以此类推(使用者可以用while循环来遍历查找结果)
void *llist_travel_find_data(LLIST *handle);
//把llist_travel_find_data函数使用的计数器清0
void llist_travel_find_rewind(LLIST *handle);

//清空链表里的数据
void llist_clean(LLIST *handle);

//链表数据排序
//升降序标志位
#define LLIST_SORT_ASC       1
#define LLIST_SORT_DESC      0
int llist_sort_cmp(int flag, llist_cmp_t *cmp, LLIST *handle);
int llist_sort(int flag, LLIST *handle);

//循环左移
//bit 指定移动多少位
void llist_shift_left(int bit, LLIST *handle);
//循环右移
//bit 指定移动多少位
void llist_shift_right(int bit, LLIST *handle);
//链表反转
void llist_rev(LLIST *handle);



//把链表存入到文件中
int llist_store(const char *file, LLIST *handle);
//从文件中读取数据并创建链表保存
LLIST *llist_load(const char *file, llist_show_t *show, llist_cmp_t *cmp, llist_destroy_t *destroy, llist_file_t *store, llist_file_t *load);

//销毁链表
void llist_destroy(LLIST **handle);

#endif /* __KYO_LLIST_H__ */
